; RUN: firtool %s -disable-all-randomization -split-input-file -lowering-options=emittedLineLength=1024 | FileCheck %s

; This is an end-to-end example of a test-bench (Foo) enabling verification,
; probing into a device-under-test (Bar), and reading from hardware which is
; only present if the verification layer is enabled.

FIRRTL version 4.0.0

circuit Foo: %[[
  {"class": "firrtl.transforms.DontTouchAnnotation", "target": "~Foo|Bar>c"},
  {"class": "firrtl.transforms.DontTouchAnnotation", "target": "~Foo|Foo>d"},
  {"class": "firrtl.transforms.DontTouchAnnotation", "target": "~Foo|VerificationHelper>w"},
  {"class": "circt.OutputDirAnnotation", "target": "~Foo|Foo", "dirname": "testbench"}
]]
  ; Collateral for the Verification layer should be output into the testbench directory.
  layer Verification, bind, "testbench":

  ; Since VerificationHelper is only used under the Verification layer, it
  ; should be output in the testbench directory too.
  module VerificationHelper:
    wire w : UInt<1>
    invalidate w

  ; Although the Component Bar is only instantiated by testbench Foo, since Bar
  ; is public, it remains in the default build directory.
  public module Bar:
    input a: UInt<1>
    output b: Probe<UInt<1>, Verification>

    ; The extracted Bar_Verification module should be placed into the
    ; testbench output directory.
    layerblock Verification:
      node c = UInt<1>(0)
      define b = probe(c)
      inst helper of VerificationHelper

  ; The TestBench module is explicitly annotated to be placed in the testbench
  ; output directory.
  public module Foo enablelayer Verification:
    inst bar of Bar
    node d = read(bar.b)
    connect bar.a, d

  ; CHECK: module Bar(
  ; CHECK:  input a
  ; CHECK: );
  ; CHECK: endmodule

  ; CHECK: FILE "testbench{{[/\]}}VerificationHelper.sv"
  ; CHECK: module VerificationHelper();
  ; CHECK:   wire w = 1'h0;
  ; CHECK: endmodule

  ; CHECK: FILE "testbench{{[/\]}}Bar_Verification.sv"
  ; CHECK: module Bar_Verification();
  ; CHECK:   wire c = 1'h0;
  ; CHECK:   wire c_probe = c;
  ; CHECK:   VerificationHelper helper ();
  ; CHECK: endmodule

  ; CHECK FILE "testbench{{[/\]}}layers-Bar-Verification.sv"
  ; CHECK: `ifndef layers_Bar_Verification
  ; CHECK:   `define layers_Bar_Verification
  ; CHECK:   bind Bar Bar_Verification verification ();
  ; CHECK: `endif // not def layers_Bar_Verification

  ; CHECK: FILE "testbench{{[/\]}}Foo.sv"
  ; CHECK: module Foo();
  ; CHECK:  wire d = Foo.bar.verification.c_probe;
  ; CHECK:   Bar bar (
  ; CHECK:   .a (d)
  ; CHECK:   );
  ; CHECK: endmodule

  ; CHECK: FILE "testbench{{[/\]}}layers-Foo-Verification.sv"
  ; CHECK: `ifndef layers_Foo_Verification
  ; CHECK:   `define layers_Foo_Verification
  ; CHECK:   `include "layers-Bar-Verification.sv"
  ; CHECK: `endif // not def layers_Foo_Verification

; // -----

; This is an end-to-end example of a test-harness enabling verification, probing
; into a device-under-test, and reading from hardware which is only present if
; the verification layer is enabled.

FIRRTL version 4.0.0

circuit TestHarness:

  layer Verification, bind:

  ; CHECK: module DUT_Verification();
  ; CHECK:   reg  [31:0] pc_d;
  ; CHECK:   wire [31:0] pc_d_probe = pc_d;
  ; CHECK:   always @(posedge DUT.clock)
  ; CHECK:     pc_d <= DUT.a;
  ; CHECK: endmodule

  ; CHECK: module DUT(
  ; CHECK:   input         clock,
  ; CHECK:   input  [31:0] a,
  ; CHECK:   output [31:0] b
  ; CHECK: );
  ; CHECK:   reg [31:0] pc;
  ; CHECK:   always @(posedge clock)
  ; CHECK:     pc <= a;
  ; CHECK:   assign b = pc;
  ; CHECK: endmodule
  module DUT:
    input clock: Clock
    input reset: UInt<1>
    input a: UInt<32>
    output b: UInt<32>
    output trace: Probe<UInt<32>, Verification>

    reg pc: UInt<32>, clock
    connect pc, a
    connect b, pc

    wire x : Probe<UInt<32>, Verification>

    layerblock Verification:
      reg pc_d: UInt<32>, clock
      connect pc_d, a
      define x = probe(pc_d)

    layerblock Verification:
      define trace = x

  ; CHECK: module TestHarness_Verification()
  ; CHECK:   `ifndef SYNTHESIS
  ; CHECK:     always @(posedge TestHarness.clock) begin
  ; CHECK:       if ((`PRINTF_COND_) & TestHarness.reset)
  ; CHECK:         $fwrite(32'h80000002, "The last PC was: %x", TestHarness.dut.verification.pc_d_probe);
  ; CHECK:     end // always @(posedge)
  ; CHECK:   `endif // not def SYNTHESIS
  ; CHECK: endmodule

  ; CHECK: module TestHarness(
  ; CHECK:   input         clock,
  ; CHECK:                 reset,
  ; CHECK:   input  [31:0] a,
  ; CHECK:   output [31:0] b
  ; CHECK: );
  ; CHECK:   DUT dut (
  ; CHECK:     .clock (clock),
  ; CHECK:     .a     (a),
  ; CHECK:     .b     (b)
  ; CHECK:   );
  ; CHECK: endmodule
  public module TestHarness:
    input clock: Clock
    input reset: UInt<1>
    input a: UInt<32>
    output b: UInt<32>

    inst dut of DUT
    connect dut.clock, clock
    connect dut.reset, reset
    connect dut.a, a
    connect b, dut.b

    layerblock Verification:
      printf(clock, reset, "The last PC was: %x", read(dut.trace))

; CHECK: FILE "layers-DUT-Verification.sv
; CHECK: `ifndef layers_DUT_Verification
; CHECK:   `define layers_DUT_Verification
; CHECK:   bind DUT DUT_Verification verification ();
; CHECK: `endif // not def layers_DUT_Verification

; CHECK: FILE "layers-TestHarness-Verification.sv"
; CHECK: `ifndef layers_TestHarness_Verification
; CHECK:   `define layers_TestHarness_Verification
; CHECK:   `include "layers-DUT-Verification.sv"
; CHECK:   bind TestHarness TestHarness_Verification verification ();
; CHECK: `endif // not def layers_TestHarness_Verification

; // -----

; This example demonstrates forcing _out_ of a layer into the outer module, a
; parent layer, or into another module.

FIRRTL version 5.1.0
circuit Foo: %[[
  {"class": "firrtl.transforms.DontTouchAnnotation", "target": "~|ForceOutOfLayer>a"},
  {"class": "firrtl.transforms.DontTouchAnnotation", "target": "~|Submodule>root"},
  {"class": "firrtl.transforms.DontTouchAnnotation", "target": "~|Submodule>a"},
  {"class": "firrtl.transforms.DontTouchAnnotation", "target": "~|Submodule>b"}
]]

  layer A, bind:
  layer B, inline:

  ; Test that forcing out of a layer into the root module works.
  ;
  ; CHECK:      module ForceOutOfLayer_A();
  ; CHECK:        initial
  ; CHECK-NEXT:     force ForceOutOfLayer.a = 2'h1;
  ; CHECK:      endmodule
  ;
  ; CHECK:      module ForceOutOfLayer();
  ; CHECK:        initial
  ; CHECK-NEXT:     force ForceOutOfLayer.a = 2'h2;
  ; CHECK:      endmodule
  module ForceOutOfLayer:

    wire a: UInt<2>
    connect a, UInt<2>(0)

    wire a_probe: RWProbe<UInt<2>>
    define a_probe = rwprobe(a)

    layerblock A:
      force_initial(a_probe, UInt<2>(1))

    layerblock B:
      force_initial(a_probe, UInt<2>(2))

  ; Test that forcing out of a layer into another works.  Test both forcing into
  ; the other module and forcing into a layer in the other module.
  ;
  ; CHECK:      module ForceIntoSubmodule_A();
  ; CHECK:        initial
  ; CHECK-NEXT:     force ForceIntoSubmodule.submodule.root = 2'h1;
  ; CHECK-NEXT:     force ForceIntoSubmodule.submodule.a.a = 2'h1;
  ; CHECK:      endmodule
  ;
  ; CHECK:      module ForceIntoSubmodule();
  ; CHECK:        initial
  ; CHECK-NEXT:     force ForceIntoSubmodule.submodule.root = 2'h2;
  ; CHECK-NEXT:     force ForceIntoSubmodule.submodule.b = 2'h2;
  ; CHECK:      endmodule
  module Submodule:
    output root_probe: RWProbe<UInt<2>>
    output a_probe: RWProbe<UInt<2>, A>
    output b_probe: RWProbe<UInt<2>, B>

    wire root: UInt<2>
    connect root, UInt<2>(0)
    define root_probe = rwprobe(root)

    layerblock A:
      wire a: UInt<2>
      connect a, UInt<2>(0)
      define a_probe = rwprobe(a)

    layerblock B:
      wire b: UInt<2>
      connect b, UInt<2>(0)
      define b_probe = rwprobe(b)

  module ForceIntoSubmodule:
    inst submodule of Submodule

    layerblock A:
      force_initial(submodule.root_probe, UInt<2>(1))
      force_initial(submodule.a_probe, UInt<2>(1))

    layerblock B:
      force_initial(submodule.root_probe, UInt<2>(2))
      force_initial(submodule.b_probe, UInt<2>(2))

  public module Foo:
    inst forceOutOfLayer of ForceOutOfLayer
    inst forceIntoSubmodule of ForceIntoSubmodule

; // -----

; LowerXMR and LowerLayers should work with nested enablelayers.  Just test that
; this doesn't error.

FIRRTL version 5.1.0
circuit Foo:

  layer A, bind:

  module Bar enablelayer A:
    input a: UInt<1>
    output b: UInt<1>

    connect b, a

  ; CHECK: module Foo(
  public module Foo enablelayer A:
    input a: UInt<1>
    output b: UInt<1>

    inst bar of Bar
    connect bar.a, a
    connect b, bar.b

; // -----

; Check that when bindfiles include eachother, the include directive uses a path
; relative to the output directory (or absolute).

FIRRTL version 5.1.0
circuit Foo:

  layer A, bind, "A":
  layer B, bind, "B":

  extmodule Baz:

  public module Bar:
    ; This instance of an extmodule prevents Foo/bar from being DCE'd.
    inst baz of Baz

  public module Foo:
    inst bar of Bar

; CHECK: FILE "A{{[/\]}}layers-Foo-A.sv"
; CHECK: `include "layers-Bar-A.sv"

; CHECK: FILE "B{{[/\]}}layers-Foo-B.sv"
; CHECK: `include "layers-Bar-B.sv"

; // -----

; Check that bindfile for Top should include layers-Bar-A, not layers-Foo-A,
; respecting the defname of an extmodule.

FIRRTL version 5.1.0
circuit Top:
  layer A, bind:

  extmodule Foo knownlayer A:
    defname = Bar

  public module Top:
    inst foo of Foo

; CHECK: `include "layers-Bar-A.sv"

; // -----

; Check that bindfile for Top should include layers-MyExt-A when defname is
; empty, falling back to the module name.

FIRRTL version 5.1.0
circuit TopEmptyDefname:
  layer A, bind:

  extmodule MyExt knownlayer A:

  public module TopEmptyDefname:
    inst ext of MyExt

; CHECK: `include "layers-MyExt-A.sv"
